package amtf

import (
	"encoding/json"
	"fmt"
	"slices"
	"strings"

	"gorm.io/gorm"
)

// 这种写法不行👇
// A自动维护字段s := []string{"created_at", "updated_at", "deleted_at"}
var A自动维护字段s = []string{"created_at", "updated_at", "deleted_at"}
var A不模糊搜索字段s = append([]string{"id"}, A自动维护字段s...)

func A成joinSQL(组件 *S组件, join字段s []*S字段, db *gorm.DB) {
	表名 := 组件.A表名
	表全部字段 := 表名 + ".*"
	var join表名 string
	var 外键字段名 string
	selectFields := []string{表全部字段}
	for _, 字段 := range join字段s {
		关联组件, join源字段, 关联字段 := A解join属性(字段)
		join表名 = 关联组件.A表名
		外键字段名 = 关联字段.A外键字段名

		本字段名 := 字段.A名称
		源字段名 := join源字段.A名称
		selectField := fmt.Sprintf("d1.%s as %s", 源字段名, 本字段名)
		selectFields = append(selectFields, selectField)
	}
	// fmt.Printf("selectFields 👉 %+v\n", selectFields)
	selectFieldsStr := strings.Join(selectFields, ", ")
	db = db.Select(selectFieldsStr)
	db.Joins(fmt.Sprintf("left join %s d1 on d1.id = %s.%s", join表名, 表名, 外键字段名))
	// 形如👇
	// db.Select(表全部字段, "d1.user_name as 用户名", "d1.nick_name as 昵称", "d1.mobile as 手机").
	// 	Joins(fmt.Sprintf("left join sys_users d1 on d1.id = %s.系统用户_用户id", 表名))
}

func A取join字段s(组件 *S组件) (join字段s []*S字段) {
	for _, 字段 := range 组件.A字段组 {
		if 字段.A类型 == A字段类型_join {
			join字段s = append(join字段s, 字段)
		}
	}
	return
}

// 直接把其他表的字段，加入到组件 字段s中的情况,👇join表的时候，会取别名，但是给 where条件的时候要用原始字段名
// SELECT 会员管理_会员.*,d1.user_name as 用户名 FROM `会员管理_会员` left join sys_users d1 on d1.id = 会员管理_会员.系统用户_用户id WHERE user_name LIKE '%cs%'
func A予字段名_有join时(组件 *S组件, 字段名 string) string {
	字段 := A字段集[A成字段id_从组件(组件, 字段名)]
	if 字段.A类型 == A字段类型_join {
		// join属性 := A解对象(字段.Ajoin属性)
		// join字段id := join属性["join字段id"]
		// _, _, join字段名 := A拆分字段id(join字段id)
		// 字段名 = join字段名
		_, join源字段, _ := A解join属性(字段)
		字段名 = join源字段.A名称
	} else {
		字段名 = 组件.A表名 + "." + 字段.A名称
	}
	return 字段名
}

// Updates 默认更新全部字段，但是排除零值字段
// 如果传入字段值的是零值，并且不使用select，则修改数据库的时候该字段会被自动排除👇
func A指定更新字段(db *gorm.DB) {
	db.Select("*").Omit("id", "created_at", "updated_at", "deleted_at")
}

// A排除部分字段s 函数用于将传入的模型转换为map，并排除指定字段
func A排除部分字段s(model any) (map[string]any, error) {
	// 将模型对象进行 JSON 编码
	data, err := json.Marshal(model)
	if err != nil {
		return nil, err
	}
	// 定义一个用于存储解码后数据的 map
	var result map[string]any
	// 将 JSON 数据解码到 result 中
	err = json.Unmarshal(data, &result)
	if err != nil {
		return nil, err
	}
	// 调用 排除部分字段s_主体 函数来排除指定字段
	排除部分字段s_主体(result)
	return result, nil
}

// 排除部分字段s_主体 函数用于递归地排除指定字段
func 排除部分字段s_主体(data any) {
	switch v := data.(type) {
	case []any:
		// 遍历切片元素
		for i := range v {
			排除部分字段s_主体(v[i])
		}
	case map[string]any:
		// 遍历 map 的键值对
		for key, value := range v {
			// 检查当前键是否在需要排除的字段列表中
			if slices.Contains(A自动维护字段s, key) {
				// 如果是，则从 map 中删除该键
				delete(v, key)
			} else {
				// 检查值是否为 map 类型
				if nestedMap, isMap := value.(map[string]any); isMap {
					// 递归调用 排除部分字段s_主体 处理嵌套的 map
					排除部分字段s_主体(nestedMap)
				} else if nestedSlice, isSlice := value.([]any); isSlice {
					// 检查值是否为切片类型
					// 递归调用 排除部分字段s_主体 处理嵌套的切片
					排除部分字段s_主体(nestedSlice)
				}
			}
		}
	}
}
